#include "EventLoop.h"
#include <csignal>
#include <memory>
#include "PlatLogger.h"
#include "XnccEventfd.h"
#include "XnccType.h"
#if defined(__CYGWIN__)
#    include <functional>
#    include <thread>
#else
#    include <sys/syscall.h>  //system call
#endif
#include <thread>
#include <utility>
#include "DateTime.h"
#include "EpollPoller.h"
#include "NoBlockPoller.h"
#include "PollPoller.h"
#include "SelectPoller.h"
#include "TimerChannel.h"
#include "Util.h"
#include "WakeupChannel.h"
namespace xncc {
#pragma GCC diagnostic ignored "-Wold-style-cast"
class IgnoreSigPipe
{
  public:
    IgnoreSigPipe() noexcept
    {
        auto ret = ::signal(SIGPIPE, SIG_IGN);
        (void)ret;
    }
};
#pragma GCC diagnostic error "-Wold-style-cast"

const IgnoreSigPipe initObj;

namespace {
    __thread pid_t cache_tid = 0;

    auto gettid() -> pid_t
    {
        if (unlikely(cache_tid == 0)) {  // 不太可能的情况 发生了
#if defined(__CYGWIN__)
            cache_tid = static_cast<pid_t>(std::hash<std::thread::id>{}(std::this_thread::get_id()));
#else
            cache_tid = static_cast<pid_t>(syscall(__NR_gettid));
#endif
        }
        return cache_tid;
    }

}  // namespace

namespace foundation {
    using namespace shared;
    using namespace types;

    EventLoop::EventLoop(types::thread_id_t id, const std::string& name, IO_MULTI_MODE::value mode)
        : id_(id), name_(name), coreId_(-1)

    {
        if (IO_MULTI_MODE::EPOLL == mode) {
            poller_ = shared::createUniquePtr<EpollPoller>();
        }
        else if (IO_MULTI_MODE::SELECT == mode) {
            poller_ = shared::createUniquePtr<SelectPoller>();
        }
        else if (IO_MULTI_MODE::NO_IO_MULTI == mode) {
            poller_ = shared::createUniquePtr<NoBlockPoller>();
        }
        else if (IO_MULTI_MODE::POLL == mode) {
            poller_ = shared::createUniquePtr<PollPoller>();
        }
        else {
            poller_ = shared::createUniquePtr<EpollPoller>();
        }
        TRACE_INFO << "EventLoop id:"_s << id << " name:"_s << name << " mode:"_s << IO_MULTI_MODE::toString(mode)
                   << " coreId:"_s << coreId_;
    }

    EventLoop::~EventLoop() = default;

    void EventLoop::init(bool isIpcLoop)
    {
        isIpcLoop_ = isIpcLoop;
        if (types::IO_MULTI_MODE::value::NO_IO_MULTI != poller_->ioType()) {
            wakeupChannel_ = std::make_shared<WakeupChannel>(this, shared::createUniquePtr<xncc::sys::EventFd>());
        }
        else {
            wakeupChannel_ = std::make_shared<WakeupChannel>(this);
        }

        wakeupChannel_->init();
        wakeupChannel_->enableReading();

        if (!isIpcLoop) {  // IPC线程不创建定时器
            timerChannel_ = std::make_shared<TimerChannel>(this);
            timerChannel_->init();
            timerChannel_->enableReading();
        }
    }

    types::IO_MULTI_MODE::value EventLoop::mode() const { return poller_->ioType(); }
    Poller*                     EventLoop::poller() { return poller_.get(); }
    void                        EventLoop::loop(int waitUs)
    {
        status_ = 1;
#if defined(__CYGWIN__)
        threadId_ = static_cast<pid_t>(std::hash<std::thread::id>{}(std::this_thread::get_id()));
#else
        threadId_ = static_cast<pid_t>(syscall(__NR_gettid));
#endif
        while (!exit_) {
            poller_->loopOnce(waitUs);
        }
    }

    int EventLoop::status() const { return status_; }

    void EventLoop::runInLoop(types::Task cb)
    {
        if (isInLoopThread() && !wakeupChannel_->isRuningPendingFunctors()) {
            cb();
        }
        else {
            wakeupChannel_->addPendingFuncs(std::move(cb));
        }
    }
    void EventLoop::assertInLoopThread(const std::string& func_name) const
    {
        if (!isInLoopThread()) {
            throw logic_exception(func_name + " must be called in loop thread");
        }
    }
    bool EventLoop::isInLoopThread() const { return threadId_ == gettid(); }

    // 添加定时任务，interval=0表示一次性任务，否则为重复任务，时间为毫秒
    types::timer_id_t EventLoop::runAt(int64_t mcroSecs, types::Task task, int64_t interval)
    {
        return timerChannel_->addTimer(std::move(task), mcroSecs, interval);
    }

    types::timer_id_t EventLoop::runAfter(int64_t mcroSecs, types::Task task, int64_t interval)
    {
        return runAt(DateTime::timeMicro() + mcroSecs, types::Task(std::move(task)), interval);
    }

    void EventLoop::cancel(types::timer_id_t timerid) { timerChannel_->cancel(timerid); }

    void EventLoop::registerUserFunc(types::message_id_t id, types::UserFunc cb)
    {
        if (userRegFuncs_.find(id) == userRegFuncs_.end()) {
            userRegFuncs_[id] = std::move(cb);
        }
        else {
            throw logic_exception("registerUserFunc id:" + std::to_string(id) + " already exist");
        }
    }

}  // namespace foundation
}  // namespace xncc